#ifndef __SYLAR_FIBER_H__
#define __SYLAR_FIBER_H__

#include <memory>
#include <functional>
#include <ucontext.h>
#include "thread.h"

namespace sylar {

class Scheduler;
// 协程类
class Fiber : public std::enable_shared_from_this<Fiber> {
  friend class Scheduler;
public:
  typedef std::shared_ptr<Fiber> ptr;

  enum State {
    // 初始化状态
    INIT,
    // 暂停状态
    HOLD,
    // 正在执行
    EXEC,
    // 终止
    TERM,
    // 准备好，可运行
    READY,
    // 异常
    EXCEPT
  };

private:
  Fiber();
public:
  Fiber(std::function<void()> cb, size_t stacksize = 0, bool use_caller = false);
  ~Fiber();

  uint64_t getId() const { return m_id; }
  State getState() const { return m_state; }

  // 重置协程函数，并重置状态
  // INIT，TERM
  void reset(std::function<void()> cb);
  // 切换到当前协程执行
  void swapIn();
  // 切换到后台执行
  void swapOut();

  void call();
  void back();
public:
  // 设置当前协程
  static void SetThis(Fiber* f);
  // 获取当前协程
  static Fiber::ptr GetThis();
  // 获取当前线程 id
  static uint64_t GetFiberId();
  // 协程切换到后台，并且设置为Ready状态
  static void YieldToReady();
  // 协程切换到后台，并且设置为Hold状态
  static void YieldToHold();
  // 总协程数
  static uint64_t TotalFibers();
  // 协程执行的方法
  static void MainFunc();
  static void CallerMainFunc();

private:
  // 协程 id
  uint64_t m_id = 0;
  // 协程栈大小
  uint32_t m_stacksize = 0;
  // 协程状态
  State m_state = INIT;

  // 协程上下文
  ucontext_t m_ctx;
  // 协程栈
  void* m_stack = nullptr;

  // 协程执行的方法
  std::function<void()> m_cb;
};

}

#endif
